package com.freemalll.merchant.common;

import com.freemalll.common.core.exception.BusinessException;
import lombok.Getter;
import org.apache.commons.collections4.map.LinkedMap;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 自动扫描 {@link Enumeration} 注解,自动注册
 *
 * @author wangw
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
 * @see Enumeration
 */
public class CommonEnum {

    /**
     * 全量枚举Map集合
     */
    public static Map<String, Class> enumsMap = new HashMap<>();
    /**
     * 全量枚举List集合
     */
    public static List<CommonEnumDto> enumsList = new ArrayList<>();

    static {
        ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AnnotationTypeFilter(Enumeration.class));
        Set<BeanDefinition> candidateComponents = provider.findCandidateComponents("com.freemalll.merchant");
        ClassLoader classLoader = provider.getResourceLoader().getClassLoader();
        for (BeanDefinition candidateComponent : candidateComponents) {
            if (candidateComponent instanceof AnnotatedBeanDefinition) {
                String beanClassName = candidateComponent.getBeanClassName();
                AnnotationMetadata metadata = ((AnnotatedBeanDefinition) candidateComponent).getMetadata();
                AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(Enumeration.class.getName()));
                Assert.state(attributes != null, "注解系统出错");
                Class<?> enumeration = ClassUtils.resolveClassName(beanClassName, classLoader);

                String id = attributes.getString("id");
                if (!StringUtils.hasLength(id) || Constant.DEFAULT_NONE.equals(id)) {
                    id = StringUtils.uncapitalize(enumeration.getSimpleName());
                    if (id.endsWith("Enum")) {
                        id = id.substring(0, id.length() - 4); // 除去Enum
                    }
                }
                addEnumToCollect(id,
                        attributes.getString("description"), enumeration);
            }
        }
    }

    public static void main(String[] args) {
        System.out.println(CommonEnum.getEnumsMap());
    }

    /**
     * 将枚举添加到Map和List集合里
     *
     * @param code
     * @param codeName
     * @param clz
     */
    public static void addEnumToCollect(String code, String codeName, Class clz) {
        enumsMap.put(code, clz);
        CommonEnumDto appEnumDto = new CommonEnumDto();
        appEnumDto.setCode(code);
        appEnumDto.setCodeName(codeName);
        appEnumDto.setChildren(enumDtoList(clz));
        enumsList.add(appEnumDto);
    }

    /**
     * 获取全量枚举Map集合
     *
     * @return
     */
    public static Map<String, Map<String, String>> getEnumsMap() {
        Map<String, Map<String, String>> result = new HashMap<>();
        for (Map.Entry<String, Class> key : CommonEnum.enumsMap.entrySet()) {
            Map<String, String> clzResult = new LinkedMap();
            for (Object clz : key.getValue().getEnumConstants()) {
                if (clz instanceof Enumerable) {
                    clzResult.put(clz.toString(), ((Enumerable) clz).getDescription());
                }
            }
            result.put(key.getKey(), clzResult);
        }
        return result;
    }

    /**
     * 获取全量枚举List集合
     *
     * @return
     */
    public static List<CommonEnumDto> getEnumsList() {
        return enumsList;
    }

    /**
     * 将枚举转化成DTO
     *
     * @param clz
     * @return
     */
    public static List<CommonEnumDto> enumDtoList(Class clz) {
        List<CommonEnumDto> appEnumDtos = new ArrayList<>();
        for (Object obj : clz.getEnumConstants()) {
            CommonEnumDto appEnumDto = new CommonEnumDto();
            if (obj instanceof Enumerable) {
                Enumerable<?> enumerable = (Enumerable<?>) obj;
                appEnumDto.setCode(enumerable.getValue());
                appEnumDto.setCodeName(enumerable.getDescription());
            }
            appEnumDtos.add(appEnumDto);
        }
        return appEnumDtos;
    }


    /***************************业务类型begin***************************************/

    /**
     * 支持场景
     */
    @Enumeration
    public enum supportingScenariosType implements Enumerable<String> {

        GREAT_HEALTH("大健康"),

        EDUCATION("教育");

        private final String desc;

        supportingScenariosType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    /**
     * 息费模式
     */
    @Enumeration
    public enum interestAndFeeModelType implements Enumerable<String> {
        NOT_HAVE("无"),
        COMMERCIAL_STICKERS("商贴"),
        GUEST_POST("客贴"),
        INTEREST_PER_MENS("月息"),
        BUSINESS_MONTH("商月");

        private final String desc;

        interestAndFeeModelType(String desc) {
            this.desc = desc;
        }

        public static String getDescByName(String name) {
            if (name == null || name.isEmpty()) {
                return null;
            }
            try {
                return valueOf(name).getDescription();
            } catch (IllegalArgumentException e) {
                return null;
            }
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    /**
     * 合作状态
     */
    @Enumeration
    public enum cooperationStatusType implements Enumerable<String> {
        NORMAL_COOPERATION("正常合作"),
        SUSPEND_COOPERATION("暂停合作"),
        TERMINATION_COOPERATION("终止合作");

        private final String desc;

        cooperationStatusType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    /**
     * 推单状态
     */
    @Enumeration
    public enum pushOrderStatusType implements Enumerable<String> {
        NORMAL_PUSH_ORDERS("正常推单"),
        PAUSE_PUSH_ORDERS("暂停推单");

        private final String desc;

        pushOrderStatusType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    /**
     * 支付方式
     */
    @Enumeration
    public enum paymentMethodType implements Enumerable<String> {
        CORPORATE_PAYMENT("对公支付"),
        PRIVATE_PAYMENT("对私支付"),
        SELF_PAYMENT("自主支付");
        private final String desc;

        paymentMethodType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    /**
     * 合作申请步骤类型
     */
    @Enumeration
    public enum cooperationApplyStepType implements Enumerable<String> {
        SUBMIT_PRELIMINARY_REVIEW("提交初审"),
        LICENSE_INFORMATION("证照信息"),
        BUSINESS_INFORMATION("经营信息"),
        OTHERS("其他资料"),
        SUPPLEMENTARY_PARTS("补件");

        private final String desc;

        cooperationApplyStepType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static cooperationApplyStepType getCooperationApplyStepType(String code) {
            for (cooperationApplyStepType type : cooperationApplyStepType.values()) {
                if (type.name().equals(code)) {
                    return type;
                }
            }
            return null;
        }
    }

    //审核申请阶段，单独给前端，跟auditType枚举值一致
    @Enumeration
    public enum cooperateApplyType implements Enumerable<String> {
        PENDING_APPROVAL("待审核"),
        APPROVING("审核中"),
        SUPPLEMENTARY_PARTS("补件中"),
        REVIEW_REFUSED("复审拒绝"),
        REVIEW_RETURNED("复审退回"),
        PENDING_SIGNING("复审通过");
        private final String desc;

        cooperateApplyType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static cooperateApplyType fromDescription(String code) {
            for (cooperateApplyType type : cooperateApplyType.values()) {
                if (type.name().equals(code)) {
                    return type;
                }
            }
            return null;
        }
    }

    //取消申请、待提交初审、初审退回、初审拒绝、待完善资料（初审通过）、待审核、审核中、待补件、复审拒绝、复审退回、待签约、已上线
    @Enumeration
    public enum auditType implements Enumerable<String> {
        WITHDRAW("取消申请"),
        SUBMIT_INITIAL_REVIEW("待提交初审"),
        INITIAL_REVIEW_RETURNED("初审退回"),
        INITIAL_REVIEW_REFUSED("初审拒绝"),
        INITIAL_REVIEW_PASSED("初审通过"),
        PENDING_APPROVAL("待审核"),
        APPROVING("审核中"),
        SUPPLEMENTARY_PARTS("待补件"),
        REVIEW_REFUSED("复审拒绝"),
        REVIEW_RETURNED("复审退回"),
        PENDING_SIGNING("审核通过"),
        ONLINE("已上线");

        private final String desc;

        auditType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static auditType fromDescription(String code) {
            for (auditType type : auditType.values()) {
                if (type.name().equals(code)) {
                    return type;
                }
            }
            return null;
        }
    }


    @Enumeration
    public enum typeOfCooperationApplicationTab implements Enumerable<String> {
        TO_DO("待办"),
        IN_REVIEW("审核中"),
        PASS_THROUGH("通过"),
        REFUSE("拒绝"),
        CANCEL("取消"),
        CONFIGURED("已配置");
        private final String desc;

        typeOfCooperationApplicationTab(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }


    @Enumeration
    public enum merchantAuditType implements Enumerable<String> {
        COLLABORATION_REVIEW("合作审核"),
        ACTIVITY_REVIEW("活动审核"),
        CHANGE_REVIEW("变更审核"),
        CONTRACT_REVIEW("合同审核"),
        INSPECTION_REVIEW("巡查审核");

        private final String desc;

        merchantAuditType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }


    @Enumeration
    public enum businessPhotoType implements Enumerable<String> {
        business_license("营业执照"),
        practice_license("医疗/卫生许可证"),
        education_license("办学许可证"),
        icp_license("ICP许可证"),
        legal_id_card_front("法人身份证正面"),
        legal_id_card_back("法人身份证反面"),
        lease_agreement("产权/租赁合同"),
        account_opening_license("开户许可证");

        private final String desc;

        businessPhotoType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }


    @Enumeration
    public enum editModuleType implements Enumerable<String> {
        MERCHANT("商户信息"),
        BUSINESS_PHOTO("证照信息"),
        CORPORATE("法人信息"),
        MEDICAL_LICENSE("执业许可证"),
        MER_VENUE_INFO("经营场所"),
        MER_ACCOUNT_LICENSE("开户信息"),
        MER_BUSINESS_INFO("商户经营信息"),
        MER_INSTALLMENT_INFO("分期信息"),
        CAPITAL_ORDER("资方顺位"),
        RECIPIENT_INFO("收款户信息");


        private final String desc;

        editModuleType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    /**
     * 申请类型
     */
    @Enumeration
    public enum applyType implements Enumerable<String> {
        NEW_COOPERATION("新户合作"),
        SUBJECT_CHANGE("主体变更"),
        ADD_NEW_BRANCHES("新增分店"),
        ADD_MAIN_STORE("新增总店");

        private final String desc;

        applyType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static applyType getApplyTypeByCode(String code) {
            for (applyType type : applyType.values()) {
                if (type.name().equalsIgnoreCase(code)) {
                    return type;
                }
            }
            return null;
        }
    }

    /**
     * 门店类型
     */
    @Enumeration
    public enum storeType implements Enumerable<String> {
        CHAIN_HEADQUARTERS("连锁总部"),
        CHAIN_MAIN_STORE("连锁直营总店"),
        CHAIN_SALES_BRANCH("连锁直营分店"),
        CHAIN_BRANCH("连锁加盟分店"),
        LOCAL_STORE("本地单店");


        private final String desc;

        storeType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static storeType getStoreTypeByCode(String code) {
            for (storeType type : storeType.values()) {
                if (type.name().equalsIgnoreCase(code)) {
                    return type;
                }
            }
            return null;
        }
    }

    /**
     * 品牌类型
     */
    @Enumeration
    public enum brandType implements Enumerable<String> {
        NATIONAL_CHAIN("全国连锁"),
        REGIONAL_CHAIN("区域连锁"),
        LOCAL_CHAIN("本地连锁"),
        SINGLE_STORE("单店");

        private final String desc;

        brandType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static brandType getBrandTypeByCode(String code) {
            for (brandType type : brandType.values()) {
                if (type.name().equalsIgnoreCase(code)) {
                    return type;
                }
            }
            return null;
        }
    }

    /**
     * 首页搜索类型
     */
    @Enumeration
    public enum homeQueryType implements Enumerable<String> {
        REVIEW_NEW_ACCOUNT("审新户"),
        CHANGE_INFO("变信息"),
        ALLOCATION_RATE("配费率"),
        SALARY_ADJUSTMENT_PARTY("调资方"),
        CHECK_MONITORING("查监控"),
        CHANGE_STATUS("改状态"),
        SEARCH_REPORT("搜报告");
        private final String desc;

        homeQueryType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static homeQueryType getByCode(String code) {
            for (homeQueryType type : homeQueryType.values()) {
                if (type.name().equalsIgnoreCase(code)) {
                    return type;
                }
            }
            return null;
        }
    }

    /**
     * 获客方式
     */
    @Enumeration
    public enum customerAcquisitionMethodType implements Enumerable<String> {
        ON_LINE("线上"),
        OFFLINE("线下");

        private final String desc;

        customerAcquisitionMethodType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static customerAcquisitionMethodType getByCode(String code) {
            for (customerAcquisitionMethodType type : customerAcquisitionMethodType.values()) {
                if (type.name().equalsIgnoreCase(code)) {
                    return type;
                }
            }
            return null;
        }
    }

    /**
     * 学校类型
     */

    @Enumeration
    public enum schoolType implements Enumerable<String> {
        yey("幼儿园"),
        zdzyxx("中等职业学校"),
        fxlgdjy("非学历高等教育机构"),
        xwpx("校外培训机构"),
        fxlwhjy("非学历文化教育类培训机构"),
        qt("其他");

        private final String desc;

        schoolType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        public static schoolType fromDescription(String code) {
            for (schoolType type : schoolType.values()) {
                if (type.name().equals(code)) {
                    return type;
                }
            }
            return null;
        }

        public static String getDescByCode(String code) {
            if (code == null) return "";
            for (schoolType e : values()) {
                if (e.name().equals(code)) return e.desc;
            }
            return "";
        }
    }

    public enum riskControlEngineType implements Enumerable<String> {
        SUBMIT_PRELIMINARY_REVIEW("提交初审"),
        OBTAIN_FUNDING("获取支持资方"),
        OBTAIN_MERCHANT_LEVEL("获取商户等级");

        private final String desc;

        riskControlEngineType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    /**
     * 商户编辑日志模块类型
     */
    public enum merchantEditLogType implements Enumerable<String> {
        RECIPIENT_INFO("收款户日志"),
        CAPITAL_ORDER("资方顺位日志"),
        MERCHANT_DETAILS("商户详情日志"),
        LICENSE_INFO("证照信息日志"),
        CORPORATE_INFO("法人信息日志"),
        PRACTICE_LICENSE("许可证信息日志"),
        PLACE_OF_BUSINESS("经营场所日志"),
        ACCOUNT_OPENING_INFO("开户信息日志"),
        BUSINESS_INFO("经营信息日志"),
        INSTALLMENT_INFO("分期信息日志"),
        RATE_INFO("费率信息日志");
        private final String desc;

        merchantEditLogType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    public enum PaymentPreferenceEnum {
        ONLY_PUBLIC("0", "仅对公"),
        ONLY_PRIVATE("1", "仅对私"),
        ONLY_SELF("2", "仅自主"),
        PRIORITY_PUBLIC("3", "优先对公"),
        PRIORITY_PRIVATE("4", "优先对私"),
        PRIORITY_SELF("5", "优先自主"),
        NO_PREFERENCE("6", "无偏好");

        private final String code;
        private final String desc;

        PaymentPreferenceEnum(String code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public String getCode() {
            return code;
        }

        public String getDesc() {
            return desc;
        }

        public static String getDescByCode(String code) {
            if (code == null) return "";
            for (PaymentPreferenceEnum e : values()) {
                if (e.code.equals(code)) return e.desc;
            }
            return "";
        }
    }

    public enum CardTypeEnum {
        PUBLIC("public", "对公"),
        SELF_PAYMENT("selfPayment","自主支付"),
        PRIVATE("private", "对私");

        private final String code;
        private final String desc;

        CardTypeEnum(String code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public String getCode() {
            return code;
        }

        public String getDesc() {
            return desc;
        }

        public static String getDescByCode(String code) {
            if (code == null) return "";
            for (CardTypeEnum e : values()) {
                if (e.code.equalsIgnoreCase(code)) return e.desc;
            }
            return "";
        }
    }

    public enum sceneCategory implements Enumerable<String> {
        DJK("大健康"),
        JY("教育");
        private final String desc;

        sceneCategory(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    public enum rateModel implements Enumerable<String> {
        APR("内部收益率"),
        IRR("年利率");
        private final String desc;

        rateModel(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    public enum RentalTypeEnum {
        RENT("1", "房屋租赁证明"),
        PROPERTY("2", "产权证明");

        private final String code;
        private final String desc;

        RentalTypeEnum(String code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public static String getDescByCode(String code) {
            for (RentalTypeEnum e : values()) {
                if (e.code.equals(code)) {
                    return e.desc;
                }
            }
            return "";
        }
    }

    public enum InterestAndFeeTypeEnum {
        COMMERCIAL_STICKERS("COMMERCIAL_STICKERS", "商贴"),
        GUEST_POST("GUEST_POST", "客贴"),
        INTEREST_PER_MENS("INTEREST_PER_MENS", "月息"),
        BUSINESS_MONTH("BUSINESS_MONTH", "商月");

        private final String code;
        private final String desc;

        InterestAndFeeTypeEnum(String code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public String getCode() {
            return code;
        }

        public String getDesc() {
            return desc;
        }

        public static String getDescByCode(String code) {
            for (InterestAndFeeTypeEnum e : values()) {
                if (e.code.equals(code)) return e.desc;
            }
            return code; // 未匹配到时原样返回
        }
    }


    public enum merchantAssetLogType implements Enumerable<String> {
        ADD("添加"),
        EDIT("编辑");
        private final String desc;

        merchantAssetLogType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }
    public enum auditCenterType implements Enumerable<String> {
        HOME_PAGE("首页"),
        AUDIT_CENTER("审核中心");
        private final String desc;

        auditCenterType(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    public enum typeOfCooperationApplicationModule implements Enumerable<String> {
        SAVE("保存"),
        SUBMIT_AUDIT("提交初审"),
        NEXT_STEP("下一步"),
        SUBMIT_FOR_REVIEW("提交复审");
        private final String desc;

        typeOfCooperationApplicationModule(String desc) {
            this.desc = desc;
        }

        @Override
        public String getDescription() {
            return desc;
        }
    }

    @Getter
    public enum CooperationApplicationModule implements Enumerable<String> {
        PRACTICE_LICENSE("PRACTICE_LICENSE", "大健康执业许可"),
        SCHOOL_LICENSE("SCHOOL_LICENSE", "教育办学许可"),
        ICP_LICENSE("ICP_LICENSE", "教育ICP许可"),
        PROPERTY_RIGHT("PROPERTY_RIGHT", "产权"),
        OPEN_AN_ACCOUNT("OPEN_AN_ACCOUNT", "开户");

        private final String code;
        private final String description;

        CooperationApplicationModule(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public static CooperationApplicationModule fromCode(String code) {
            for (CooperationApplicationModule module : values()) {
                if (module.getCode().equals(code)) {
                    return module;
                }
            }
            throw BusinessException.businessDataNotExist("未知的模块类型");
        }
    }

    @Getter
    public enum OtherDataModel implements Enumerable<String> {
        INSTALLMENT_INFO("INSTALLMENT_INFO", "分期信息"),
        RECIPIENT_INFO("RECIPIENT_INFO", "收款户信息"),
        INVESTOR_INFO("INVESTOR_INFO", "资方顺位"),
        RATE_INFO("RATE_INFO", "费率信息");


        private final String code;
        private final String description;

        OtherDataModel(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public static OtherDataModel fromCode(String code) {
            for (OtherDataModel module : values()) {
                if (module.getCode().equals(code)) {
                    return module;
                }
            }
            throw BusinessException.businessDataNotExist("未知的模块类型");
        }
    }

    @Getter
    public enum SubmitBusinessInfoModel implements Enumerable<String> {
        BUSINESS_INFO("BUSINESS_INFO", "营业信息"),
        BUSINESS_FILE("BUSINESS_FILE", "营业附件信息");

        private final String code;
        private final String description;

        SubmitBusinessInfoModel(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public static SubmitBusinessInfoModel fromCode(String code) {
            for (SubmitBusinessInfoModel module : values()) {
                if (module.getCode().equals(code)) {
                    return module;
                }
            }
            throw BusinessException.businessDataNotExist("未知的模块类型");
        }
    }
}
